/*
 * Funny Language - a free style programming language.
 * Copyright (C) 2015 by fanguangping (fanguangping@163.com)
 *
 */


#include <stdlib.h>
#include "runner_trans.h"

Queue *__wrap_get_mappings(Statement *s) {
    /*
    Queue *queue = init_queue();
    Mapping *mapping1 = create_sys_mapping_1(); // {define template {name}: {template} as {statement}}
    Mapping *mapping2 = create_mapping_1(); // {{x} + {y}} -> {(+ {x} {y})}
    Mapping *mapping3 = create_mapping_2(); // {{x} or {y}} -> {(or {x} {y})}
    Mapping *mapping4 = create_mapping_3(); // {case {when {a} then {b} , ...} else {c}} -> {(cond {({a} {b}) ...} (else {c}))}
    enqueue(queue, mapping1);
    enqueue(queue, mapping2);
    enqueue(queue, mapping3);
    enqueue(queue, mapping4);
    return queue;
    */
    check_expected(s);
    return (Queue *)mock();
}

String __wrap_expand_lex(String text) {
    check_expected(text);
    return (String)mock();
}

String __wrap_match(Statement *source) {
    check_expected(source);
    return (String)mock();
}

static void test_match_one_arg_when_lex_expanded() {
    Statement *statement = init_arg();
    add_statement(statement, "{3+4i}", SYM);

    expect_string(__wrap_expand_lex, text, "{3+4i}");
    will_return(__wrap_expand_lex, "(make-complex (lex \"Integer\" \"3\") (lex \"Integer\" \"4\"))");

    String result = match_one_arg(statement);
    assert_string_equal(result, "(make-complex (lex \"Integer\" \"3\") (lex \"Integer\" \"4\"))");
}

/*
static void test_match_one_arg_when_mapping_source_contains_one_arg() {
    //{source} -> {target}
    Mapping *m = (Mapping *) malloc(sizeof(Mapping));
    m->sys = NULL;
    m->isMacro = FALSE;
    m->className = "";
    m->functionName = "";
    m->source = copy_string("{source}");
    m->target = copy_string("{target}");
    m->sourceStatement = init_arg();
    m->targetStatement = init_arg();
    add_statement(m->sourceStatement, "{source}", SYM);
    add_statement(m->targetStatement, "{target}", SYM);
    m->starter = to_dfa(m->sourceStatement);

    Queue *queue = init_queue();
    enqueue(queue, m);
}
*/

static void test_match_original_when_mapping_source_matched() {
    //{this is source statement} -> {this is target statement}
    Mapping *m = (Mapping *) malloc(sizeof(Mapping));
    m->sys = NULL;
    m->isMacro = FALSE;
    m->className = "";
    m->functionName = "";
    m->source = copy_string("{this is source statement}");
    m->target = copy_string("{this is target statement}");
    m->sourceStatement = init_arg();
    m->targetStatement = init_arg();
    add_statement(m->sourceStatement, "this", SYM);
    add_statement(m->sourceStatement, "is", SYM);
    add_statement(m->sourceStatement, "source", SYM);
    add_statement(m->sourceStatement, "statement", SYM);
    add_statement(m->targetStatement, "this", SYM);
    add_statement(m->targetStatement, "is", SYM);
    add_statement(m->targetStatement, "target", SYM);
    add_statement(m->targetStatement, "statement", SYM);
    m->starter = to_dfa(m->sourceStatement);
    Queue *queue = init_queue();
    enqueue(queue, m);

    Statement *statement = init_arg();
    add_statement(statement, "this", SYM);
    add_statement(statement, "is", SYM);
    add_statement(statement, "source", SYM);
    add_statement(statement, "statement", SYM);

    expect_value(__wrap_get_mappings, s, statement);
    will_return(__wrap_get_mappings, queue);

    String result = match_original(statement);
    assert_string_equal(result, "this is target statement");
}

static void test_match_original_when_mapping_source_not_matched() {
    Statement *statement = init_arg();
    add_statement(statement, "this", SYM);
    add_statement(statement, "is", SYM);
    add_statement(statement, "source", SYM);
    add_statement(statement, "statement", SYM);

    expect_value(__wrap_get_mappings, s, statement);
    will_return(__wrap_get_mappings, init_queue());

    String result = match_original(statement);
    assert_string_equal(result, "this is source statement");
}

// {when {a} then {b} ...}
static Statement *create_loop_statement() {
    Statement *s = (Statement *)malloc(sizeof(Statement));
    Statement *arg1 = NULL;
    Statement *arg2 = NULL;
    s->symbol = NULL;
    s->type = LOOP;
    s->children = init_queue();
    add_statement(s, "when", SYM);
    arg1 = add_statement(s, NULL, ARG);
    add_statement(arg1, "a", SYM);
    add_statement(s, "then", SYM);
    arg2 = add_statement(s, NULL, ARG);
    add_statement(arg2, "b", SYM);
    add_statement(s, "...", SYM);
    return s;
}

static Statement *simple_arg(String name) {
    Statement *statement = init_arg();
    add_statement(statement, name, SYM);
    return statement;
}

static void test_match_loop_statement_when_matched() {
    expect_string(__wrap_expand_lex, text, "cond1");
    will_return(__wrap_expand_lex, "{cond1}");
    expect_string(__wrap_expand_lex, text, "a");
    will_return(__wrap_expand_lex, "{a}");
    expect_string(__wrap_expand_lex, text, "cond2");
    will_return(__wrap_expand_lex, "{cond2}");
    expect_string(__wrap_expand_lex, text, "b");
    will_return(__wrap_expand_lex, "{b}");
    expect_string(__wrap_expand_lex, text, "cond3");
    will_return(__wrap_expand_lex, "{cond3}");
    expect_string(__wrap_expand_lex, text, "c");
    will_return(__wrap_expand_lex, "{c}");

    Queue *replaceQueue = init_queue();
    add_key_value(replaceQueue, "a", simple_arg("cond1"));
    add_key_value(replaceQueue, "b", simple_arg("a"));
    add_key_value(replaceQueue, "a", simple_arg("cond2"));
    add_key_value(replaceQueue, "b", simple_arg("b"));
    add_key_value(replaceQueue, "a", simple_arg("cond3"));
    add_key_value(replaceQueue, "b", simple_arg("c"));

    Statement *statement = create_loop_statement();
    String result = match_loop_statement(statement, replaceQueue, 3);

    assert_string_equal(result, " when {cond1} then {a}  when {cond2} then {b}  when {cond3} then {c} ");
}

static void test_match_loop_statement_when_contains_empty_statement() {
    expect_string(__wrap_expand_lex, text, "cond1");
    will_return(__wrap_expand_lex, "{cond1}");
    expect_string(__wrap_expand_lex, text, "a");
    will_return(__wrap_expand_lex, "{a}");

    Queue *replaceQueue = init_queue();
    add_key_value(replaceQueue, "a", simple_arg("cond1"));
    add_key_value(replaceQueue, "b", simple_arg("a"));
    add_key_value(replaceQueue, "a", init_arg()); //empty statement
    add_key_value(replaceQueue, "b", simple_arg("b"));
    add_key_value(replaceQueue, "a", simple_arg("cond3"));
    add_key_value(replaceQueue, "b", simple_arg("c"));

    Statement *statement = create_loop_statement();
    String result = match_loop_statement(statement, replaceQueue, 3);
    assert_null(result);
}


static void test_match_loop_statement_when_not_matched() {
    Statement *statement = create_loop_statement();

    Mapping *mapping1 = create_mapping_1(); // {{x} + {y}} -> {(+ {x} {y})}
    Mapping *mapping2 = create_mapping_2(); // {{x} or {y}} -> {(or {x} {y})}


    expect_value(__wrap_match, statement, mapping1->sourceStatement);
    will_return(__wrap_match, "{x-plus-y}");

    expect_value(__wrap_match, statement, parse("{a}"));
    will_return(__wrap_match, "{a}");
    expect_value(__wrap_match, statement, mapping2->sourceStatement);
    will_return(__wrap_match, "{x-or-y}");

    expect_value(__wrap_match, statement, parse("{b}"));
    will_return(__wrap_match, "{b}");
    expect_value(__wrap_match, statement, parse("{cond3}"));
    will_return(__wrap_match, "{cond3}");
    expect_value(__wrap_match, statement, parse("{c}"));
    will_return(__wrap_match, "{c}");



    expect_value(__wrap_get_mappings, s, statement);
    will_return(__wrap_get_mappings, init_queue());


    Queue *replaceQueue = init_queue();
    add_key_value(replaceQueue, "a", mapping1->sourceStatement);
    add_key_value(replaceQueue, "b", simple_arg("a"));
    add_key_value(replaceQueue, "a", mapping2->sourceStatement);
    add_key_value(replaceQueue, "b", simple_arg("b"));
    add_key_value(replaceQueue, "a", simple_arg("cond3"));
    add_key_value(replaceQueue, "b", simple_arg("c"));


    String result = match_loop_statement(statement, replaceQueue, 3);

    printf("%s\n", result);
}


int main(int argc, char **argv) {
    const struct CMUnitTest tests[] = {
            cmocka_unit_test(test_match_one_arg_when_lex_expanded),
            cmocka_unit_test(test_match_original_when_mapping_source_matched),
            cmocka_unit_test(test_match_original_when_mapping_source_not_matched),
            cmocka_unit_test(test_match_loop_statement_when_matched),
            cmocka_unit_test(test_match_loop_statement_when_contains_empty_statement),
            cmocka_unit_test(test_match_loop_statement_when_not_matched),
    };
    return cmocka_run_group_tests(tests, setup_translate, teardown_translate);
}


/*

#include <assert.h>
#include <string.h>
#include "../ds/test_ds.h"
#include "../../src/translate/dfa.h"
#include "../../src/translate/parser.h"
#include "../../src/translate/init.h"
#include "test_dfa.h"

void test_match_one_arg() {
	load();
	assert(match_one_arg(NULL) == NULL);
	assert(strcmp(match_one_arg(parse("{+}")), "+") == 0);
	assert(strcmp(match_one_arg(parse("{true}")), "true") == 0);
	assert(strcmp(match_one_arg(parse("{false}")), "false") == 0);
}

void test_orignal_statement() {
	load();
	assert(!orignal_statement(NULL));
	assert(orignal_statement(parse("{abc}")));
	assert(orignal_statement(parse("{a b c}")));
	assert(orignal_statement(parse("{'(a b c)}")));
	assert(!orignal_statement(parse("{a {b} c}")));
}

void test_match_orignal() {
	load();
	assert(match_orignal(NULL) == NULL);
	assert(strcmp(match_orignal(parse("{abc}")), "abc") == 0);
	assert(strcmp(match_orignal(parse("{a b c}")), "a b c") == 0);
	assert(strcmp(match_orignal(parse("{'(a b c)}")), "'(a b c)") == 0);
	assert(match_orignal(parse("{a {b} c}")) == NULL);
}

void test_test_match() {
	;
}

void test_match4test() {
	load();
	assert(match(NULL) == NULL);
	assert(strcmp(match(parse("{abc}")), "abc") == 0);
	assert(strcmp(match(parse("{a b c}")), "a b c") == 0);
	assert(strcmp(match(parse("{'(a b c)}")), "'(a b c)") == 0);
	assert(match(parse("{a {b} c}")) == NULL);
}

void test_dfa() {
	test_match_one_arg();
	test_orignal_statement();
	test_match_orignal();
	test_test_match();
	test_match4test();
}

 * */